/*
 * Copyright 2018 Zhongan.com All right reserved. This software is the
 * confidential and proprietary information of Zhongan.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with Zhongan.com.
 */

package com.zhongan.cloud.gateway.filter.limit;

import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

import reactor.core.publisher.Mono;

/**
 * 限流过滤器管理。<br/>
 * 实现参考类org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint
 *
 * @author tongyufu
 * @since 2018年7月10日 上午10:28:34
 */
@RestController
@RequestMapping("/filter/limit")
public class RateLimitAction implements ApplicationEventPublisherAware {

    @Autowired
    private RouteDefinitionWriter     routeDefinitionWriter;
    private ApplicationEventPublisher publisher;

    /**
     * 创建限流器
     */
    @RequestMapping("create")
    public Mono<String> create() {
        RouteDefinition routeDefinition = new RouteDefinition();
        PredicateDefinition predicateDefinition = new PredicateDefinition();
        Map<String, String> predicateParams = new HashMap<>(8);
        Map<String, String> filterParams = new HashMap<>(8);
        FilterDefinition filterDefinition = new FilterDefinition();
        URI uri = UriComponentsBuilder.fromUriString("lb://HELLO-SERVICE").build().toUri();

        routeDefinition.setId("rateLimitTest");
        // 名称是固定的，spring gateway会根据名称找对应的PredicateFactory
        predicateDefinition.setName("Path");
        predicateParams.put("pattern", "/rate/**");
        predicateDefinition.setArgs(predicateParams);

        // 名称是固定的，spring gateway会根据名称找对应的FilterFactory
        filterDefinition.setName("RequestRateLimiter");
        // 每秒最大访问次数
        filterParams.put("redis-rate-limiter.replenishRate", "2");
        // 令牌桶最大容量
        filterParams.put("redis-rate-limiter.burstCapacity", "3");
        // 限流策略(#{@BeanName})
        filterParams.put("key-resolver", "#{@hostAddressKeyResolver}");
        // 自定义限流器(#{@BeanName})
        //filterParams.put("rate-limiter", "#{@redisRateLimiter}");
        filterDefinition.setArgs(filterParams);

        routeDefinition.setPredicates(Arrays.asList(predicateDefinition));
        routeDefinition.setFilters(Arrays.asList(filterDefinition));
        routeDefinition.setUri(uri);
        routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
        publisher.publishEvent(new RefreshRoutesEvent(this));
        return Mono.just("success");
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }
}
